﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using MvcExtensions.Attributes;

namespace MvcExtensions.Extensions
{
    public static class DataExtensions
    {
        public static void UpdateLookupText<T>(T model)
            where T : class
        {
            var properties = model.GetType().GetProperties();

            foreach (var pinfo in properties)
            {
                if (pinfo.PropertyType.IsClass && pinfo.PropertyType != typeof(string))
                {
                    var value = pinfo.GetValue(model);

                    if (pinfo.PropertyType.IsGenericType)
                    {
                        var genericParamType = pinfo.PropertyType.GenericTypeArguments[0];
                    }
                }
                else
                {
                    var lookupTextAttrb = pinfo.GetCustomAttributes(typeof(LookupTextAttribute))
                                               .ToList()
                                               .FirstOrDefault() as LookupTextAttribute;

                    if (lookupTextAttrb != null)
                    {
                        var lookuppInfo = properties
                            .FirstOrDefault(x => x.Name == lookupTextAttrb.LookupIdPropertyName);

                        if (lookuppInfo != null)
                        {
                            var lookupValue = lookuppInfo.GetValue(model);

                            var lookItems = ControlExtensions.GetLookItems(lookuppInfo);

                            var lookupText = lookItems
                                .FirstOrDefault(x => x.Id == lookupValue.ToString() || x.Key == lookupValue.ToString());

                            if (lookupText != null) pinfo.SetValue(model, lookupText.Description);
                        }
                    }
                }
            }
        }

        private static readonly ConcurrentDictionary<Type, IList<Lookup>> StaticCachedLookup = new ConcurrentDictionary<Type, IList<Lookup>>();

        public static IEnumerable<Lookup> GetEnumLookup<T>(T enumType)
            where T : Type
        {
            return StaticCachedLookup.GetOrAdd(enumType, (x) => GetEnumLookupList(x).ToList());
        }

        public static IEnumerable<Lookup> GetEnumLookupList<T>(T enumType)
            where T : Type
        {
            var returnList = new List<Lookup>();

            foreach (var fieldInfo in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
            {
                var lookup = new Lookup
                    {
                        Id = Enum.Parse(enumType, fieldInfo.Name).ToString(),
                        Key = ((int)Enum.Parse(enumType, fieldInfo.Name)).ToString(),
                    };
                var dscrAttributes = fieldInfo.GetCustomAttributes<DescriptionAttribute>().ToList();
                lookup.Description = dscrAttributes.Any() ? dscrAttributes.First().Description : fieldInfo.Name;
                returnList.Add(lookup);
            }

            return returnList;
        }

        public static string PascalCaseToString(this string str, string replacement = " ")
        {
            var regex = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z])|(?<=[^A-Z])(?=[A-Z])|(?<=[A-Za-z])(?=[^A-Za-z])");
            return regex.Replace(str, replacement);
        }
    }
}